// Container Types
type Seq [out T]
    native; // container.Seq
type List [out T]
    native; // container.List, ([] T)
type Set [out T]
    native; // container.Set
type Map [out K, out V]
    native; // container.Map
type Queue [out T]
    native; // container.Queue
type PriorityQueue [out T]
    native; // container.PriorityQueue


// Container Operations

/* Functions for Seq[T] */

export method Seq.List: List[T]
    native '__SeqToList';

export method Seq.empty: Bool
    &(seq) => { not seq.{shift}.Bool };

export function shift:[T]
    &(Seq[T]) => Maybe[(T,Seq[T])]
    native '__SeqShift';

export const Nil:
    Seq[never]
    native '__SeqNil';
export function cons:[T]
    &(T,Seq[T]) => Seq[T]
    native '__SeqCons';
export function prepend:[T]
    &(Seq[T],T) => Seq[T]
    &(seq,head) => (head cons seq);

export function Seq:
    & { initial: Number, count: Number } => Seq[Number]
    native '__SeqCount';
export function Seq:
    & { from: Number, to: Number } => Seq[Number]
    native '__SeqInclusiveRange';

export function map:[A,B]
    &(Seq[A], &(A) => B) => Seq[B]
    native '__SeqMap';
export function deflate-map:[A,B]
    &(Seq[A], &(A) => Maybe[B]) => Seq[B]
    native '__SeqDeflateMap';
export function filter:[T]
    &(Seq[T], &(T) => Bool) => Seq[T]
    native '__SeqFilter';
export function flat-map:[A,B]
    &(Seq[A], &(A) => Seq[B]) => Seq[B]
    native '__SeqFlatMap';

export function scan:[T,A]
    &(Seq[T], A, &(A,T) => A) => Seq[A]
    native '__SeqScan';
export function scan:[T,A]
    &(Seq[T], (A, &(A,T) => A)) => Seq[A]
    &(seq, opts) => let (init,f) := opts, { scan (seq,init,f) };
export function reduce:[T,A]
    &(Seq[T], A, &(A,T) => A) => A
    native '__SeqReduce';
export function reduce:[T,A]
    &(Seq[T], (A, &(A,T) => A)) => A
    &(seq, opts) => let (init,f) := opts, { reduce (seq,init,f) };
export function apply-all:[T]
    &(T, Seq[&(T) => T]) => T
    &(init, @f) => @f.{ reduce (init, &(x,f) => { f(x) }) };

export function some:[T]
    &(Seq[T], &(T) => Bool) => Bool
    native '__SeqSome';
export function every:[T]
    &(Seq[T], &(T) => Bool) => Bool
    native '__SeqEvery';
export function find-first:[T]
    &(Seq[T], &(T) => Bool) => Maybe[T]
    native '__SeqGetFirst';
export function get-first:[T,X]
    &(Seq[T], &(T) => Maybe[X]) => Maybe[X]
    native '__SeqMapFirst';

export function zip:[A,B]
    &(Seq[A],Seq[B]) => Seq[(A,B)]
    native '__SeqZip';
export function zip-longest:[A,B]
    &(Seq[A],Seq[B]) => Seq[(Maybe[A],Maybe[B])]
    native '__SeqZipLongest';
export function zip:[T]
    &(List[Seq[T]]) => Seq[List[T]]
    native '__SeqZipList';
export function zip-longest:[T]
    &(List[Seq[T]]) => Seq[List[Maybe[T]]]
    native '__SeqZipLongestList';
export function with-index:[T]
    &(Seq[T]) => Seq[(T,Number)]
    native '__SeqWithIndex';
export function chunk:[T]
    &(Seq[T], Number) => Seq[List[T]]
    native '__SeqChunk';
export function concat:[T]
    &(List[Seq[T]]) => Seq[T]
    &(list) => (list.{Seq} flat-map &(items) => items);


/* Functions of List[T] */

export method List.Seq: Seq[T]
    native '__ListToSeq';
export method List.length: Number
    native '__ListLength';
export method List.empty: Bool
    native '__ListEmpty';

export function reverse:[T]
    &(List[T]) => List[T]
    native '__ListReverse';

export function shift:[T]
    &(List[T]) => Maybe[(T,List[T])]
    native '__ListShift';
export function pop:[T]
    &(List[T]) => Maybe[(List[T],T)]
    native '__ListPop';

export function map:[A,B]
    &(List[A], &(A) => B) => List[B]
    &(list, f) => { Seq list } .{ map f } .{ List };
export function filter:[T]
    &(List[T], &(T) => Bool) => List[T]
    &(list, f) => { Seq list } .{ filter f } .{ List };
export function reduce:[T,A]
    &(List[T], (A, &(A,T) => A)) => A
    &(list, opts) => { Seq list } .{ reduce opts };
export function scan:[T,A]
    &(List[T], (A, &(A,T) => A)) => List[A]
    &(list, opts) => { Seq list } .{ scan opts } .{ List };
export function some:[T]
    &(List[T], &(T) => Bool) => Bool
    &(list, p) => ({ Seq list } some p);
export function every:[T]
    &(List[T], &(T) => Bool) => Bool
    &(list, p) => ({ Seq list } every p);
export function find-first:[T]
    &(List[T], &(T) => Bool) => Maybe[T]
    &(list, p) => ({ Seq list } find-first p);
export function get-first:[T,X]
    &(List[T], &(T) => Maybe[X]) => Maybe[X]
    &(list, f) => ({ Seq list } get-first f);
export function flat-map:[A,B]
    &(List[A], &(A) => List[B]) => List[B]
    &(list, f) => (list.{Seq} flat-map &(item) => { f item }.{Seq}).{List};
export function concat:[T]
    &(List[List[T]]) => List[T]
    &(list) => (list.{Seq} flat-map &(items) => items.{Seq}).{List};

/* Functions of Set[T] */
function Set:[T]
    &(List[T], Op<>[T]) => Set[T]
    native '__Set';
export function Set:[T]
    { <>: Op<>[T] }
    &(List[T]) => Set[T]
    &(items) => { Set (items, <>) };
export function has:[T]
    &(Set[T], T) => Bool
    native '__SetHas';

/* Functions of Map[K,V] */
function Map:[K,V]
    &(List[(K,V)], Op<>[K]) => Map[K,V]
    native '__Map';
export function Map:[K,V]
    { <>: Op<>[K] }
    &(List[(K,V)]) => Map[K,V]
    &(entries) => { Map (entries, <>) };
export function List:[K,V]
    &(Map[K,V]) => List[(K,V)]
    native '__MapEntries';
export function get:[K,V]
    &(Map[K,V], K) => Maybe[V]
    native '__MapGet';
export function insert:[K,V]
    &(Map[K,V], (K, V)) => Maybe[Map[K,V]]
    native '__MapInsert';
export function insert*:[K,V]
    &(Map[K,V], (K, V)) => Map[K,V]
    native '__MapInsertCasual';
export function delete:[K,V]
    &(Map[K,V], K) => Maybe[(V,Map[K,V])]
    native '__MapDelete';
export function delete*:[K,V]
    &(Map[K,V], K) => Map[K,V]
    native '__MapDeleteCasual';


